// import { h1 } from './m1';
// console.log(h1)
console.log(Promise)

// string number boolean 

let title: string = "学习ts";
title = `好好 ${title}`
console.log(title)
let isDone: boolean = false;
let dec: number = -9;
dec = 1
 
// 数组类型 type[] Array<type>

// 方法一：数组泛型
let from: Array<number> = [1, 2, 3]
// 方法二：具有 number 类型的数组 
let arr: number[] = [4, 5, 6]
// arr = []
// arr = ['a'] // error

// 元组 Tuple：固定长度的数组

let x: [string, number]
x = ['hello', 10] // 必须一一对应
// console.log(x.substr()) // 不能使用字符串的方法
// console.log(x[4]) // 不能越界访问

// 枚举 enum

// enum Color {
//     Red, Green, Blue
// }
// let c: Color = Color.Green
// console.log(c); // 1
enum Color {
    Red = 2, Green = 5, Blue = 9
}
let c: Color = Color.Green
console.log(c); // 5
let colorName: string = Color[5]
console.log(colorName)
// var colorName = Color[3];
// console.log(colorName); // undefined

// 自动类型推断 & any

// let notSure = 5 // 默默的赋值一个类型 number
// notSure = 'hello' // 报错
// let notSure: any = 5
// notSure = "hello" 
// notSure.abc() // 不报错 但是编译后js有可能报错
let notSure: number = 5
notSure = 6 
notSure.toFixed() // 不报错
let list: any[] = ['a', true, 4]

// void
// javascript: void(0) // js中默认事件消失ts中是无返回值
function echo(): void{
    return 
}
// let unusable: void = undefined 
// let unusable: void = 9 // 报错

// 联合类型/复合类型  应用函数参数较多

let day: string | number | boolean
day = '一'
day = 3
// day.length 允许类型更换，但是不能混用方法
day = true
day = 'a'

// & 表示同时
let j: {name: string} & {age: number}
j = {name: '孙悟空', age: 18}

// never

function error(message: string): never { // 应用在抛出错误，没有返回值的情况
    throw new Error()
}

// null undefined

// Symbols 可以作为对象的唯一标识
let sym1 = Symbol('key') // es6
let sym2 = Symbol('key') 
console.log(sym1 === sym2)  

// 类型别名
// type
type Point = {
    x: number;
    y: number;
}

type ID = number | string
type UserInputSanitizedString = string

/* 报错了
let sym = Symbol()
let obj = {
    [sym]: 'value'
}
console.log(obj[sym])

const getClass = Symbol();
class C {
    [getClass]() {
        return 'hello'
    }
}
let c = new C()
console.log(c[getClass]())
*/

// 函数

function sum(x: number, y: number){
    return x + y;
}
let mySum = function(x: number, y: number) {
    return x + y;
}
sum(3, 4)
mySum(4, 5)

// 定义函数的返回类型
let mySum2: (x:number, y: number)=> number = function(x: number, y: number){
    return x + y
}
// 设置函数结构的类型声明：语法（形参：类型，形参：乐行...）=> 返回值
let mySum3: (x: number,y :number) => number;
mySum3 = function(x: number, y: number): number{
    return x + y
}

// 接口方式定义函数

interface SearchFunc {
    (source: string, subString: string): boolean
}

let mySource: SearchFunc = function(source: string, subString: string): boolean{
    return source.search(subString) != -1
}

// 可选参数 不能写在前面 可以加默认参数
function buildName(firstName: string, lastName: string){

}
function buildName2(firstName: string = 'Tom', lastName?: string){

}
let tomcat = buildName("Tom", "Cat");
let tom1 = buildName2("Tom");
let tom2 = buildName2(undefined, 'Cat');

function push(array: any[], ...items: any){
    items.forEach(function(item: any){
        array.push(item)
    })
    return array
}
let a:Array<any> = []
push(a, 1, 2, 3)
console.log(a)

// 重载
function reverse(x: number): number
function reverse(x: string): string
function reverse(x: number | string): number|string {
    if(typeof x === 'number'){
        return Number(x.toString().split('').reverse().join())
    }else{
        return x.split('').reverse().join()
    }
}

// 接口

// interface Person {
//     name: string,
//     age?: number // 加?可选
// }
// let tom: Person = {
//     name: 'Tom',
//     age: 25
// }
// name必填 age可填可不填 其他随意填
interface Person {
    // readonly name: string, // 只读
    name: string,
    age?: number, // 加?可选
    [propName: string]: any // 索引签名
}
let tom: Person = {
    name: 'Tom',
    age: 25,
    from: ''
}
tom.name = 'tom'

// 扩展接口
/* interface IAnimal {
    name: string
}
interface Bear extends IAnimal {
    honey: boolean
}
const bear: Bear = {
    name: 'winnie',
    honey: true
}

// type 交叉扩展
type TAnimal = {
    name: string
}
type Bear = TAnimal & {
    honey: Boolean
}

// 向现有的类型添加字段
interface MyWindow {
    count: number
}
interface MyWindow {
    title: string
}
const w: MyWindow = {
    title: '111',
    count: 100
} */

// 类型创建后是不能更改的  类型别名 type 不能通过同名的方式拓展的

// 类
class Animal {
    // name: string = 'tomcat'
    // constructor(name: string){ // 这里声明后又赋值会累赘
    //     // console.log(0)
    //     this.name = name
    // }

    constructor(public name: string){ // public
        // console.log(0)
        this.name = name
    }

    sayName(): string{
        return this.name
    }
}
// 类的继承
class Cat extends Animal {
    constructor(public name:string){
        super(name)  // 方法，调用父类里面你的constructor函数
    }
    // sayName(){ // 重名，不能覆盖会报错
    sayHi(){
        console.log(this.name)
    }
}
let animal = new Animal('Tomcat')
console.log(animal.name)
let cat = new Cat('Tomcat') 
console.log(cat.name)

// 存储器类似vue的计算属性
class Animal2 {
    constructor(public name: string){
        this.name = name
    }
    static isAnimal(a: any){ // 静态方法
        return a instanceof Animal2
    }
    get surname(){
        return this.name
    }
    set surname(value:string){
        this.name = value
    }
}
let b = new Animal2('kitty')
b.surname = 'Tom'
console.log(b.surname)
console.log(Animal2.isAnimal(b)) //true 静态方法 在类上面直接调用
let cc = 0
console.log(Animal2.isAnimal(c)) // false

class Animal3 {
    static abc = 'aaa' // es7
    constructor(public name: string){
        this.name = name
    }
}
console.log(Animal3.abc)

// 修饰符
// public 默认，子类实例都可以访问
// class Animal4 {
//     public name: string = ''
//     public sayName(){
//         console.log(this.name)
//     }
// }
class Animal4 {
    name: string = ''
    private sayName(){
        console.log(this.name)
    }
}
class Cat4 extends Animal4 {
    sayHi(){
        console.log(this.name)
    }
}
let ani = new Animal4()
// private 子类 实例都不可访问
// ani.name 私有的  

// protected 子类可以访问，实例不可以访问
class Animal5 {
    readonly name: string = ''
    protected sayName(){
        console.log(this.name)
    }
}
class Cat5 extends Animal5 {
    sayHi(){
        // this.name = '' // readonly 只读不能更改
        console.log(this.name)
    }
}
let ani5 = new Animal5()
// ani5.name

// 抽象类
abstract class Animals {
    public abstract render():void // 抽象方法
    // 抽象类可以定义非抽象方法
    public getProps(){
        return 'props'
    }
}
// let animals = new Animals() 抽象类不能实例化

class Cats extends Animals {
    render(){ // 抽象类继承
        return '<div></div>'
    }
}

let cats = new Cats()
// cats.render

// 类的类型
// let a: Cat = new Animal()
// let b: Animal = new Cat()

